﻿namespace Summoner
{
    using System.Collections.Generic;

    public class LRUDictionary<TKey, TValue>
    {
        private int _capacity;
        private IDictionary<TKey, TValue> _dictionary;
        private LinkedList<TKey> _linkedList;

        public LRUDictionary(int capacity = 100)
        {
            this._capacity = capacity;
            this._dictionary = new Dictionary<TKey, TValue>();
            this._linkedList = new LinkedList<TKey>();
        }

        public void Set(TKey key, TValue value)
        {
            this._dictionary[key] = value;
            this._linkedList.Remove(key);
            this._linkedList.AddFirst(key);
            if (this._linkedList.Count > this._capacity)
            {
                this._dictionary.Remove(this._linkedList.Last.Value);
                this._linkedList.RemoveLast();
            }
        }

        public bool TryGet(TKey key, out TValue value)
        {
            bool b = this._dictionary.TryGetValue(key, out value);
            if (b)
            {
                this._linkedList.Remove(key);
                this._linkedList.AddFirst(key);
            }
            return b;
        }

        public bool ContainsKey(TKey key)
        {
            return this._dictionary.ContainsKey(key);
        }

        public void Remove(TKey key)
        {
            if(this._dictionary.ContainsKey(key))
            {
                this._linkedList.Remove(key);
                this._dictionary.Remove(key);
            }
        }

        public int Count
        {
            get
            {
                return this._dictionary.Count;
            }
        }

        public int Capacity
        {
            get
            {
                return this._capacity;
            }
            set
            {
                if (value > 0 && this._capacity != value)
                {
                    this._capacity = value;
                    while (this._linkedList.Count > this._capacity)
                    {
                        this._linkedList.RemoveLast();
                    }
                }
            }
        }

        public TValue this[TKey key]
        {
            get
            {
                this._linkedList.Remove(key);
                this._linkedList.AddFirst(key);
                return this._dictionary[key];
            }
            set
            {
                this._linkedList.Remove(key);
                this._linkedList.AddFirst(key);
                this._dictionary[key] = value;
            }
        }

        public ICollection<TKey> Keys
        {
            get
            {
                return this._dictionary.Keys;
            }
        }

        public ICollection<TValue> Values
        {
            get
            {
                return this._dictionary.Values;
            }
        }
    }
}